package mymap.utils.map;

import mymap.web.beans.Quadro;

public class GMapUtil {

	// propriedades que serao utilizadas para calcular
	// o deslocamento do centro da imagem
	public static final int offset = 268435456;
	public static final double radius = offset / Math.PI;

	/**
	 * @param lat - latitude atual do mapa
	 * @param lng - longitude atual do mapa
	 * @param deltaX - deslocamento em Y para o novo centro do mapa (em pixels)
	 * @param deltaY - deslocamento em X para o novo centro do mapa (em pixels)
	 * @param z - nivel de zoom
	 * @return { 0 - longitude, 1 - latitude}
	 */
	public static double[] adjust(double lat, double lng, int deltaX,
			int deltaY, int z) {
		return new double[] { XToL(LToX(lng) + (deltaX << (21 - z))),
				YToL(LToY(lat) + (deltaY << (21 - z))) };
	}

	/**
	 * retorna a nova longitude a partir de uma distancia X em pixels
	 * @param lng
	 * @param deltaX
	 * @param z
	 * @return
	 */
	public static double toLongitude(double lng, int deltaX, int z){
		return XToL(LToX(lng) + (deltaX << (21 - z)));
	}
	
	/**
	 * retorna a nova latitude a partir de uma distancia Y em pixels
	 * @param lat
	 * @param deltaY
	 * @param z
	 * @return
	 */
	public static double toLatitude(double lat, int deltaY, int z){
		return YToL(LToY(lat) + (deltaY << (21 - z)));
	}
	
	/**
	 * @param lat - latitude atual do mapa
	 * @param lng - longitude atual do mapa
	 * @param deltaX - deslocamento em Y para o novo centro do mapa (em pixels)
	 * @param deltaY - deslocamento em X para o novo centro do mapa (em pixels)
	 * @param z - nivel de zoom
	 * @return longitude,latitude
	 */
	public static String getNewCenter(double lat, double lng, int deltaX,
			int deltaY, int z) {
		double[] center = adjust(lat, lng, deltaX, deltaY, z);
		return center[1] + "," + center[0];
	}

	
	/**
	 * retorna a posicao o do pixel a partir da latitude e zoom do mapa
	 * 
	 * @param lat
	 * @param zoom
	 * @return
	 */
	public static int getYFromLat(double lat, int zoom) {

		double sinLatitude = Math.sin(lat * Math.PI / 180);

		double pixelY = (0.5 - Math.log((1 + sinLatitude) / (1 - sinLatitude))
				/ (4 * Math.PI))
				* 256 * Math.pow(2, zoom);

		return (int) pixelY;
	}

	public static int getXFromLong(double lng , int zoom){
		return new Double(LToX(lng)).intValue() >> (21-zoom);
	}
	
	
	
	/**
	 * Retorna a distancia em pixel entre duas latitudes
	 * @param lat1
	 * @param lat2
	 * @param zoom
	 * @return
	 */
	public static Integer getDistLatPixel(double lat1, double lat2, int zoom){
		return Math.abs(getYFromLat(lat1, zoom) - getYFromLat(lat2, zoom));
	}
	
	/**
	 * Retorna a distancia em pixel entre duas longitudes
	 * @param lng
	 * @param lng2
	 * @param zoom
	 * @return
	 */
	public static Integer getDistLongPixel(double lng, double lng2, int zoom){
		return Math.abs(getXFromLong(lng, zoom) - getXFromLong(lng2, zoom));
	}
	

	
	private static double LToX(double x) {
		return Math.round(offset + radius * x * Math.PI / 180);

	}
	
	private static double LToY(double y) {
		return Math.round(offset - radius
				* Math.log((1 + Math.sin(y * Math.PI / 180))
						/ (1 - Math.sin(y * Math.PI / 180))) / 2);
	}
	
	private static double XToL(double x) {
		return ((Math.round(x) - offset) / radius) * 180 / Math.PI;
	}
	
	private static double YToL(double y) {
		return (Math.PI / 2 - 2 * Math.atan(Math.exp((Math.round(y) 
				- offset)/ radius))	) * 180 / Math.PI;
	}
	
	public static Quadro getQuadro(Integer x, Integer y, Double latInicial, Double longInicial, int zoom){
		
		Quadro quadro = new Quadro(x, y, y.toString()+ x.toString());
		
		int deltaY = ((Quadro.SIZE / 2) + y * Quadro.SIZE );// * -1;
		int deltaX = (Quadro.SIZE / 2) + x * Quadro.SIZE;

		double[] center = adjust(latInicial, longInicial, deltaX, deltaY, zoom);
		
		Double longCenter = center[0];
		Double latCenter = center[1];
		
		quadro.setLatCenter(latCenter);
		quadro.setLongCenter(longCenter);
		
		return quadro;
	}
}
